/*
 * @Author: sonss
 * @Date: 2024-08-27 11:00:26
 * @LastEditTime: 2024-08-28 19:47:17
 * @FilePath: /ss-file-antd/src/components/Assets/FilePanel.tsx
 * @Description:  资源文件
 */

import '@/assets/css/assets_file.scss';
import CateEditModule from '@/pages/Assets/Category/modules/Edit';
import { Trees } from '@/services/assets_category';
import { Remove, Save, Search } from '@/services/assets_file';
import { CheckOutlined, FileOutlined, VideoCameraOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import type { MenuProps } from 'antd';
import {
  Button,
  Col,
  Dropdown,
  Empty,
  Flex,
  Input,
  Pagination,
  Popconfirm,
  Row,
  Spin,
  Tree,
  TreeDataNode,
} from 'antd';
import { MenuInfo } from 'rc-menu/lib/interface';
import { Key, ReactNode, useEffect, useState } from 'react';
import ButtonUpload from '../Upload/Button';
import { SceneEnum } from '@/enums/assets_file';

type AssetsFilePanelProps = {
  title?: string;
  onSelect?: (files: ASSETS.FILE.Row[] | undefined) => void;
};

const AssetsFilePanel: React.FC<AssetsFilePanelProps> = (props) => {
  const [cateTreeSource, setCateTreeSource] = useState<TreeDataNode[]>([]);
  const [treeExpandedKeys, setTreeExpandedKeys] = useState<Key[]>([]);
  const [treeSelectedKeys, setTreeSelectedKeys] = useState<Key[]>(['0']);
  const [fileParams, setFileParams] = useState<ASSETS.FILE.SearchParams>({});
  const [filePager, setFilePager] = useState<{ page?: number; pageSize: number }>({
    page: 1,
    pageSize: 18,
  });
  const [fileTotal, setFileTotal] = useState<number>(0);
  const [fileList, setFileList] = useState<ASSETS.FILE.Row[]>([]);
  const [fileLoading, setFileLoading] = useState<boolean>(false);
  const [searchValue, setSearchValue] = useState<string>();
  const [fileCheckedKeys, setFileCheckedKeys] = useState<Key[]>([]);
  const [cateEditor, setCateEditor] = useState<ASSETS.CATEGORY.Info | undefined>();

  const TREE_ALL_KEY = '0';

  const reloadCateTrees = (options?: { onSuccess?: (vals: TreeDataNode[]) => void }) => {
    const parse = (child: ASSETS.CATEGORY.Tree, pid?: Key | undefined) => {
      const tree: TreeDataNode = {
        title: child.name,
        key: child.id + '',
      };

      if (pid) {
        tree.key = pid + '-' + tree.key;
      }

      if (child.children && child.children.length > 0) {
        tree.children = child.children.map((v) => parse(v, tree.key));
      }
      return tree;
    };

    Trees().then((res) => {
      if (res.code !== 0) {
        return;
      }

      const values = (res.data?.list || []).map((v) => parse(v));
      values.unshift({
        key: TREE_ALL_KEY,
        title: '全部(根)',
      });
      setCateTreeSource(values);

      if (options && options.onSuccess) {
        options.onSuccess(values);
      }
    });
  };

  const reloadFiles = (force?: boolean) => {
    setFileLoading(true);
    setFileTotal(0);
    setFileList([]);
    setFileCheckedKeys([]);

    const req: ASSETS.FILE.SearchRequest = {
      ...fileParams,
      page: filePager.page || 1,
      pageSize: filePager.pageSize || 18,
    };

    if (force) {
      req.page = 1;
    }

    Search(req)
      .then((res) => {
        if (res.code !== 0) {
          return;
        }

        setFileTotal(res.data?.total || 0);
        setFileList(res.data?.list || []);
      })
      .finally(() => {
        setFileLoading(false);
      });
  };

  useEffect(() => {
    reloadCateTrees({
      onSuccess: (vals: TreeDataNode[]) => {
        setTreeExpandedKeys(vals.slice(0, 3).map((v) => v.key));
      },
    });
    reloadFiles();
  }, []);

  useEffect(() => {
    reloadFiles(true);
  }, [fileParams]);

  useEffect(() => {
    reloadFiles(false);
  }, [filePager]);

  const refresh = (force?: boolean) => {
    reloadFiles(force);
  };

  const handleTreeExpand = (keys: Key[]) => {
    setTreeExpandedKeys(keys);
  };

  const handleTreeSelect = (keys: Key[]) => {
    if (keys.length < 1) {
      return;
    }

    setTreeSelectedKeys(keys);

    const params: ASSETS.FILE.SearchParams = {
      ...fileParams,
      categoryId: undefined,
    };
    if (keys.length > 0) {
      params.categoryId = keys
        .map((v) => (v ? Number((v as string).split('-').pop()) : undefined))
        .filter((v) => v !== undefined)
        .filter((v) => v !== 0);
      if (params.categoryId.length < 1) {
        params.categoryId = undefined;
      }
    }
    setFileParams(params);
  };

  const handleUploadChange = (file: UPLOADER.FileInfo) => {
    const req: ASSETS.FILE.SaveForm = {
      scene: file.scene,
      fileName: file.fileName,
      fileSize: file.size,
      fileExt: file.ext,
      fileType: file.mimeType,
      filePath: file.filePath,
      fileUrl: file.url,
    };

    // 塞入分类
    if (fileParams.categoryId) {
      if (Array.isArray(fileParams.categoryId)) {
        if (fileParams.categoryId.length > 0) {
          req.arrCategoryId = fileParams.categoryId;
        }
      } else {
        req.arrCategoryId = [fileParams.categoryId];
      }
    }

    Save(req).then((res) => {
      if (res.code !== 0) {
        return;
      }
      refresh();
    });
  };

  const onFilePageChange = (page: number, pageSize: number) => {
    setFilePager({
      page,
      pageSize,
    });
  };

  const handleFileSearch = (value: string) => {
    setFileParams({
      ...fileParams,
      words: value,
    });
  };

  const handleFileCheck = (idx: number) => {
    const list = [...fileList];
    list[idx].checked = list[idx].checked ? false : true;
    setFileList(list);
    setFileCheckedKeys(list.filter((v) => v.checked).map((v) => v.id!));

    if (props.onSelect) {
        props.onSelect(list.filter(v => v.checked))
    }
  };

  const buildCover = (item: ASSETS.FILE.Row) => {
    switch (item.scene) {
      case SceneEnum.IMAGE:
        return <div className="cover" style={{ backgroundImage: `url(${item.fileUrl})` }} />;
        break;

      case SceneEnum.MEDIA:
        return (
          <div className="cover">
            <VideoCameraOutlined className="icon-file" />
          </div>
        );
        break;

      default:
        return (
          <div className="cover">
            <FileOutlined className="icon-file" />
          </div>
        );
    }
  };

  const content =
    fileList && fileList.length > 0 ? (
      <Row gutter={[10, 10]}>
        {fileList.map((item, idx) => (
          <Col span={4} key={`file_${idx}`}>
            <div className="file-item" onClick={() => handleFileCheck(idx)}>
              {buildCover(item)}
              <div className="desc" title={item.fileName}>
                {item.fileName}
              </div>
              {item.checked && (
                <div className="mask">
                  <CheckOutlined className="icon" />
                </div>
              )}
            </div>
          </Col>
        ))}
      </Row>
    ) : (
      <Flex justify="center" align="center" style={{ height: '100%' }}>
        <Empty />
      </Flex>
    );

  const handleFileCheckedRemove = () => {
    const req: ASSETS.FILE.RemoveForm = {
      ids: fileCheckedKeys.map((v) => v as number),
    };
    setFileLoading(true);
    Remove(req)
      .then((res) => {
        if (res.code !== 0) {
          return;
        }
        refresh();
      })
      .finally(() => {
        setFileLoading(false);
      });
  };

  const treeMenus: MenuProps['items'] = [
    {
      label: '添加',
      key: 'tree:add',
    },
  ];

  const handleCateAdd = (node: TreeDataNode) => {
    const key = (node.key as string).split('-')?.pop();
    setCateEditor({
      parentId: key ? Number(key) : 0,
    });
  };

  const handleTreeMenuClick = (e: MenuInfo, node: TreeDataNode) => {
    switch (e.key) {
      case 'tree:add':
        handleCateAdd(node);
        break;
    }
  };

  const rendTreeTitle = (node: TreeDataNode) => {
    return (
      <Dropdown
        menu={{ items: treeMenus, onClick: (e) => handleTreeMenuClick(e, node) }}
        trigger={['contextMenu']}
      >
        <div>{node.title as ReactNode}</div>
      </Dropdown>
    );
  };

  const handleCateEditClose = () => {
    setCateEditor(undefined);
  };

  const handleCateEditSuccess = () => {
    reloadCateTrees();
    handleCateEditClose();
  };

  return (
    <>
      <ProCard title={props.title} split="vertical" style={{ height: '600px' }}>
        <ProCard colSpan="200px">
          <Tree
            treeData={cateTreeSource}
            showLine={true}
            expandedKeys={treeExpandedKeys}
            selectedKeys={treeSelectedKeys}
            onExpand={handleTreeExpand}
            onSelect={handleTreeSelect}
            className="card-tree"
            titleRender={rendTreeTitle}
          />
        </ProCard>
        <ProCard>
          <Spin spinning={fileLoading}>
            <div className="box-file">
              <div className="head">
                <div className="search-form">
                  <Input.Search
                    size="small"
                    placeholder="输入关键词查询"
                    value={searchValue}
                    onSearch={handleFileSearch}
                    onChange={(e) => setSearchValue(e.target.value)}
                    allowClear={true}
                  />
                </div>
                <ButtonUpload btnSize="small" multiple={true} onChange={handleUploadChange} />
              </div>
              <div className="inner">{content}</div>
              <div className="foot">
                <div className="actions">
                  {fileCheckedKeys.length > 0 && (
                    <>
                      <span>已选择 {fileCheckedKeys.length} 项</span>
                      <Popconfirm title="确定要删除吗？" onConfirm={handleFileCheckedRemove}>
                        <Button size="small" className="btn">
                          删除
                        </Button>
                      </Popconfirm>
                    </>
                  )}
                </div>
                <Pagination
                  size="small"
                  onChange={onFilePageChange}
                  total={fileTotal}
                  current={filePager.page}
                  pageSize={filePager.pageSize}
                  hideOnSinglePage={true}
                  showSizeChanger={false}
                />
              </div>
            </div>
          </Spin>
        </ProCard>
      </ProCard>
      {cateEditor && (
        <CateEditModule
          record={cateEditor}
          onSuccess={handleCateEditSuccess}
          onClose={handleCateEditClose}
        />
      )}
    </>
  );
};

export default AssetsFilePanel;
